﻿using System;
using System.Runtime.InteropServices;

using Epic.Core;

namespace Epic.HandyExtensions
{
    public static class FloatLexicalConversionExtensions
    {
#pragma warning disable 1591

        const uint UIntMidPoint = 0x80000000;
        const int IntMidMask = (int)~UIntMidPoint;
        const ulong ULongMidPoint = UIntMidPoint * 0x100000000u;
        const long LongMidMask = (long)~ULongMidPoint;

        #region 64位

        #region 有符号整数

        /// <summary>
        /// 根据给定的双精度浮点数，计算出一个在排序场合与其等价的 64 位有符号整数。
        /// </summary>
        public static long ToSortableInt64(this double value)
        {
            //long tmp = *(long*)(&value);
            //var tmp = new DoublePayload { Double = value }.Int64;
            var tmp = new Unchecked<double, long> { ValueA = value }.ValueB;

            if (tmp < 0)
            {
                tmp ^= LongMidMask;
            }

            return tmp;
        }

        /// <summary>
        /// 从给定的 64 位有符号整数，计算出其所代表的双精度浮点数。
        /// </summary>
        public static double ToSortableDouble(this long value)
        {
            if (value < 0)
            {
                value ^= LongMidMask;
            }

            //return new DoublePayload { Int64 = value }.Double;
            return new Unchecked<long, double> { ValueA = value }.ValueB;

            //return *(double*)&value;
        }

        #endregion

        #region 无符号整数

        /// <summary>
        /// 根据给定的双精度浮点数，计算出一个在排序场合与其等价的 64 位无符号整数。
        /// </summary>
        [CLSCompliant(false)]
        public static ulong ToSortableUInt64(this double value)
        {
            //ulong tmp = *(ulong*)(&value);
            //var tmp = new DoublePayload { Double = value }.UInt64;
            var tmp = new Unchecked<double, ulong> { ValueA = value }.ValueB;

            if (tmp < ULongMidPoint)
            {
                tmp ^= ULongMidPoint;
            }
            else
            {
                tmp = ~tmp;
            }

            return tmp;
        }

        /// <summary>
        /// 从给定的 64 位无符号整数，计算出其所代表的双精度浮点数。
        /// </summary>
        [CLSCompliant(false)]
        public static double ToSortableDouble(this ulong value)
        {
            if (value < ULongMidPoint)
            {
                value = ~value;
            }
            else
            {
                value ^= ULongMidPoint;
            }

            //return new DoublePayload { UInt64 = value }.Double;
            return new Unchecked<ulong, double> { ValueA = value }.ValueB;

            //return *(double*)(&value);
        }

        #endregion

        #endregion

        #region 32位

        #region 有符号整数

        /// <summary>
        /// 根据给定的单精度浮点数，计算出一个在排序场合与其等价的 32 位有符号整数。
        /// </summary>
        public static int ToSortableInt(this float value)
        {
            //int tmp = *(int*)(&value);

            //var tmp = new SinglePayload { Single = value }.Int32;
            var tmp = new Unchecked<float, int> { ValueA = value }.ValueB;

            if (tmp < 0)
            {
                tmp ^= IntMidMask;
            }

            return tmp;
        }

        /// <summary>
        /// 从给定的 32 位有符号整数，计算出其所代表的单精度浮点数。
        /// </summary>
        public static float ToSortableSingle(this int value)
        {
            if (value < 0)
            {
                value ^= IntMidMask;
            }

            //return new SinglePayload { Int32 = value }.Single;
            return new Unchecked<int, float> { ValueA = value }.ValueB;

            //return *(float*)&value;
        }

        #endregion

        #region 无符号整数

        /// <summary>
        /// 根据给定的单精度浮点数，计算出一个在排序场合与其等价的 32 位无符号整数。
        /// </summary>
        [CLSCompliant(false)]
        public static uint ToSortableUInt(this float value)
        {
            //uint tmp = *(uint*)(&value);

            //var tmp = new SinglePayload { Single = value }.UInt32;
            var tmp = new Unchecked<float, uint> { ValueA = value }.ValueB;

            if (tmp < UIntMidPoint)
            {
                tmp ^= UIntMidPoint;
            }
            else
            {
                tmp = ~tmp;
            }

            return tmp;
        }

        /// <summary>
        /// 从给定的 32 位无符号整数，计算出其所代表的单精度浮点数。
        /// </summary>
        [CLSCompliant(false)]
        public static float ToSortableSingle(this uint value)
        {
            if (value < UIntMidPoint)
            {
                value = ~value;
            }
            else
            {
                value ^= UIntMidPoint;
            }

            //return new SinglePayload { UInt32 = value }.Single;
            return new Unchecked<uint, float> { ValueA = value }.ValueB;

            //return *(float*)(&value);
        }

        #endregion

        #endregion

    }
}
